/**
 * @author wuliang
 * @Email  wuliang@boqii.com
 */

/**
 * 命名空间 namespace
 */
var WL = {};

/**
 * Interface Calss  鸭式辩型法
 * 两个参数
 * name : 接口实例名称
 * methods : 接口实例方法集合(数组)
 */
WL.Interface = function (name, methods) {
    // 判断参数个数，必须为两个
    if (arguments.length != 2) {
        throw new Error('This instance interface constructor arguments lenght must be 2!');
    }

    this.name = name;
    // 定义一个空数组对象，用于接收methods变量传入的元素(方法名称)
    this.methods = [];

    for (var i = 0, len = methods.length; i < len; i++) {
        // 判断methods变量中的元素(方法名称)类型是不是字符串
        if (typeof methods[i] !== 'string') {
            throw new Error('This instance method name is error!');
        }
        this.methods.push(methods[i]);
    }
}; // Interface class end

/**
 * Interface static method
 * 用于检测对象是否全部实现接口的方法
 * @param object
 */
WL.Interface.ensureImplements = function (object) {
    // 判断参数个数，至少是两个 检测对象  检测对象实现的接口1..
    if (arguments.length < 2) {
        throw new Error('Interface.ensureImplements constructor arguments must be > 2 !');
    }

    // 获得检测对象实现的接口
    for (var i = 1, len = arguments.length; i < len; i++) {
        var instanceInterface = arguments[i];
        // 判断接口对象是否是接口类型
        if (instanceInterface.constructor !== WL.Interface) {
            throw new Error('This instance constructor is not Interface class!');
        }

        // 判断检测对象是否全部实现接口对象的方法
        for (var j = 0; j < instanceInterface.methods.length; j++) {
            // 定义一个变量，用来接收接口实例的方法名
            var methodName = instanceInterface.methods[j];
            // 如果检测对象中不存在接口实例方法
            // 或者存在但不是一个方法，则表示没有实现
            if (!object[methodName] || typeof object[methodName] !== 'function') {
                throw new Error("The method '"+ methodName +"()' is not found! ");
            }
        }
    }
}; // Interface.ensureImplements end

/**
 * extend method
 * 用于实现只继承父类的原型对象
 * @param sub
 * @param sup
 */
WL.extend = function (sub,sup) {
    // 定义一个空函数用于中转
    var F = new Function();
    // 将父类的原型对象赋给空函数的原型对象
    F.prototype = sup.prototype;
    // 子类继承父类的原型
    sub.prototype = new F();
    // 还原子类的构造器
    sub.prototype.constructor = sub;
    // 定义一个子类的静态属性，用于 保存父类的原型对象
    // 一方面：方便解耦  另一方面：便于获得父类的原型对象
    sub.supperClass = sup.prototype;
    // 还原父类原型对象的构造器
    if (sup.prototype.constructor == Object.constructor) {
        sup.prototype.constructor = sup;
    }
}; // extends end

/**
 * EventUtil class
 * 单体模式，跨浏览器事件处理类
 * 在该类中会封装一系列事件
 */
WL.EventUtil = {
    /**
     * 注册事件
     * @param element 要绑定事件的元素
     * @param type    要绑定的事件类型
     * @param handler 绑定的事件函数
     */
    addHandler:function(element , type , handler){
        if(element.addEventListener){		//FF
            element.addEventListener(type,handler,false);
        } else if(element.attachEvent){		//IE
            element.attachEvent('on'+type , handler);
        }
    } ,

    /**
     * 移除事件
     * @param element  要绑定事件的元素
     * @param type     要绑定的事件类型
     * @param handler  绑定的事件函数
     */
    removeHandler:function(element , type , handler){
        if(element.removeEventListener){		//FF
            element.removeEventListener(type,handler,false);
        } else if(element.detachEvent){		//IE
            element.detachEvent('on'+type , handler);
        }
    }
}; // EventUtil end

/**
 * 扩展数组原型对象
 * 遍历数组元素 (可以是多维数组)
 * @param fn
 * @returns {Array}
 */
Array.prototype.each = function (fn) {
    try {
        // 计数器，用于记录遍历数组的元素位置
        this.i || (this.i = 0);
        // 只要当数组不是空数组并且传入的参数是 Function 类型的时候  才去遍历数组
        if (this.length > 0 && fn.constructor === Function) {
            // 循环遍历数组元素
            while (this.i < this.length) {
                // 获取数组中的每一个元素
                var e = this[this.i];
                if (e && e.constructor === Array) { // 元素还是数组类型的
                    // 递归调用自身处理
                    e.each(fn);
                } else { // 是单个元素，直接调用传入的函数处理
                    fn.call(e, e);
                }
                this.i++;
            }
            // 循环结束，将计数器置为 null ，释放内存
            this.i = null;
        }
    } catch (ex) {
        // do something ....
    }

    return this;
}; // each method end